package com.hgz.utilspackage.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * 数据库操作工具类
 * @author 小志
 * @date 2025/1/9 - 14:47
 */
public class DBUtil {
    //1.定义成员变量 DataSource
    private static DataSource ds;

    static {
        //静态加载properties文件，获取里面的值
        Properties properties = new Properties();
        try {
            properties.load(DBUtil.class.getClassLoader().getResourceAsStream("db.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取连接
     * @return 连接对象
     */
    public static Connection getConnection() throws SQLException {
        return  ds.getConnection();
    }

    /**
     * 关闭连接释放资源
     * @param resultSet 结果集对象
     * @param preparedStatement 预处理对象
     * @param conn 连接对象
     */
    public static void close(ResultSet resultSet, PreparedStatement preparedStatement, Connection conn){
        try {
            if (resultSet != null) {
                resultSet.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException("关闭ResultSet时发生错误", e);
        }
        try {
            if (preparedStatement != null) {
                preparedStatement.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException("关闭PreparedStatement时发生错误", e);
        }
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException("关闭Connection时发生错误", e);
        }
    }

    /**
     * 执行修改，删除，添加语句
     * @param conn 连接对象
     * @param sql 要运行的sql语句
     * @param params 注入的参数
     * @return 返会受影响行数
     * @throws SQLException sql异常
     */
    public static int executeUpdate(Connection conn, String sql, List<Object> params) throws SQLException {
        PreparedStatement pstmt = null;
        boolean flag = false;
        try {
            if (conn == null) {
                conn = getConnection();
                flag = true;
            }
            pstmt = conn.prepareStatement(sql);
            setParams(pstmt, params);
            return pstmt.executeUpdate();
        } finally {
            if(flag){
                close(null,pstmt,conn);
            }else{
                close(null,pstmt,null);
            }
        }
    }

    /**
     * 只执行一条语句，不需要控制连接关闭
     * @param sql 要执行的sql语句
     * @param params 注入参数
     * @return 返回是否成功
     */
    public static int executeUpdate(String sql, List<Object> params) throws SQLException {
        return executeUpdate(null, sql, params);
    }

    /**
     * 执行添加语句获取自增id
     * @param sql sql
     * @param params 参数
     * @return 当前的id
     * @throws SQLException 异常
     */
    public static int executeUpdateAddGetID(Connection conn, String sql, List<Object> params) throws SQLException {
        PreparedStatement pstmt = null;
        boolean flag = false;
        int count = 0;
        try {
            if (conn == null) {
                conn = getConnection();
                flag = true;
            }
            pstmt = conn.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);
            setParams(pstmt, params);
            count = pstmt.executeUpdate();

            if (count > 0) {
                // 获取自增 ID
                try (ResultSet generatedKeys = pstmt.getGeneratedKeys()) {
                    if (generatedKeys.next()) {
                        count = generatedKeys.getInt(1);
                    }
                }
            }

        }finally {
            if(flag){
                close(null,pstmt,conn);
            }else{
                close(null,pstmt,null);
            }
        }
        return count;
    }

    /**
     * 只执行一条语句，不需要控制连接关闭
     * @param sql 要执行的sql语句
     * @param params 注入参数
     * @return 返回是否成功
     */
    public static int executeUpdateAddGetID(String sql, List<Object> params) throws SQLException {
        return executeUpdateAddGetID(null, sql, params);
    }

    /**
     * 执行查询语句方法
     * @param conn 传入的连接
     * @param sql 需要执行的sql语句
     * @param params 注入的参数
     * @param fieldMapping 数据返回的映射字段
     * @param clazz 当前泛型的字节码文件
     * @return 当前对象的list集合
     * @throws SQLException sql 异常
     */
    public static  <T> ArrayList<T> executeQuery(Connection conn, String sql, List<Object> params, Map<String,String> fieldMapping, Class<T> clazz) throws SQLException {
        ArrayList<T> arrayList = null;
        PreparedStatement pstmt = null;
        ResultSet resultSet = null;
        boolean flag = false;
        try {
            // 声明对象
            arrayList = new ArrayList<T>();

            if (conn == null) {
                conn = getConnection();
                flag = true;
            }

            pstmt = conn.prepareStatement(sql);
            // 注入参数
            setParams(pstmt,params);
            // 获取结果集
            resultSet = pstmt.executeQuery();

            // 数据存储进数组
            while(resultSet.next()){
                arrayList.add(getInfo(resultSet,fieldMapping,clazz));
            }

        } finally {
            if(flag){
                close(resultSet,pstmt,conn);
            }else{
                close(resultSet,pstmt,null);
            }
        }

        return arrayList;
    }

    /**
     * 只执行一条语句，不需要控制连接关闭
     * @param sql 需要执行的sql语句
     * @param params 注入的参数
     * @param fieldMapping 数据返回的映射字段
     * @param clazz 当前泛型的字节码文件
     * @return 当前对象的list集合
     * @throws SQLException sql 异常
     */
    public static <T> ArrayList<T>  executeQuery(String sql, List<Object> params, Map<String,String> fieldMapping, Class<T> clazz) throws SQLException {
        return executeQuery(null, sql, params,fieldMapping,clazz);
    }

    /**
     * 插入预处理语句的参数
     * @param stmt 预处理对象
     * @param params 注入的参数
     * @throws SQLException sql异常
     */
    private static void setParams(PreparedStatement stmt, List<Object> params) throws SQLException {
        for (int i = 0; i < params.size(); i++) {
            stmt.setObject(i + 1, params.get(i));
        }
    }

    /**
     * 多条sql语句 事务执行
     * @param conn 连接
     * @param sqls 运行的sql语句集合
     * @param paramsList 参数集合
     * @return 是否成功
     */
    public static boolean executeTransaction(Connection conn, List<String> sqls, List<List<Object>> paramsList) {
        boolean flag = true;
        try {
            conn.setAutoCommit(false); // 开启事务
            for (int i = 0; i < sqls.size(); i++) {
                String sql = sqls.get(i);
                List<Object> params = paramsList.get(i);
                executeUpdate(conn, sql, params);
            }
            conn.commit(); // 提交事务
        } catch (SQLException e) {
            try {
                conn.rollback(); // 回滚事务
                flag = false;
            } catch (SQLException ex) {
                throw new RuntimeException("回滚事务失败", ex);
            }
        } finally {
            try {
                conn.setAutoCommit(true); // 恢复默认设置
                conn.close(); // 关闭连接
            } catch (SQLException e) {
                throw new RuntimeException("关闭连接失败", e);
            }
        }
        return flag;
    }

    /**
     * 获取当前的对象
     * @param resultSet 要获取的结果集
     * @param fieldMapping 要映射的字段啊
     * @param clazz 当前对象的字节码文件
     * @return 返回当前的对象
     */
    private static  <T> T getInfo(ResultSet resultSet, Map<String, String> fieldMapping, Class<T> clazz){
        //1.新建对象
        T entity = null;
        try {
            entity = clazz.getDeclaredConstructor().newInstance();
            //2.获取所有字段
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                //使用暴力反射操作字段
                field.setAccessible(true);
                //获取集合映射字段
                String columnName = fieldMapping.get(field.getName());
                if(columnName != null){
                    Class<?> fieldType = field.getType();//对象字段类型
                    Object value = resultSet.getObject(columnName);//数据库字段数据
                    // value = resultSet.getObject("123");
                    if (value != null) {//对比字段类型在进行强制转换
                        if (fieldType == Integer.class || fieldType == int.class) {//Integer类型
                            value = ((Number) value).intValue();
                        } else if (fieldType == Double.class || fieldType == double.class) {//Double类型
                            value = ((Number) value).doubleValue();
                        } else if (fieldType == Long.class || fieldType == long.class) {//Long类型
                            value = ((Number) value).longValue();
                        } else if (fieldType == Float.class || fieldType == float.class) {//Float类型
                            value = ((Number) value).floatValue();
                        } else if (fieldType == byte[].class) {//byte[]数组类型
                            value = resultSet.getBytes(columnName);
                        } else if (fieldType == Date.class) {//Date时间类型
                            value = resultSet.getDate(columnName);
                        } else if (fieldType == Timestamp.class) {//Timestamp时间类型
                            value = resultSet.getTimestamp(columnName);
                        }
                    }
                    //赋值
                    field.set(entity,value);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return entity;
    }
}
